﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using FXSStation.Modules.SharedInfrastructureModule.Extentions.TileView;
using Microsoft.Practices.Composite.Events;
using Microsoft.Practices.Composite.Regions;
using FXSStation.Modules.SharedInfrastructureModule.BusinessClasses.Accounts;
using System.Collections.ObjectModel;
using FXSStation.Modules.SharedInfrastructureModule.BusinessClasses.Currency;
using FXSStation.Modules.SharedInfrastructureModule.BusinessClasses.Chart;
using FXSStation.Modules.SharedInfrastructureModule.BusinessClasses.Common;
using FXSStation.Modules.SharedInfrastructureModule.Events;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.ComponentModel;
using UIComposition.Infrastructure;

namespace FXSStation.Modules.SettingsModule
{
    /// <summary>
    /// Interaction logic for AccountSettingsView.xaml
    /// </summary>
    public partial class AccountSettingsView : UserControl, ITileViewItem, IAccountRepository, INotifyPropertyChanged
    {
        private ObservableCollection<Account> _accountRepository;
        private event EventHandler SimulationStarted;
        public IEventAggregator _eventAggregator { get; set; }
        public SubscriptionToken _subscriptionToken { get; set; }
        private Account _currentAccout;
        public Account CurrentAccount
        {
            get
            {
                return _currentAccout;
            }
            set
            {
                if (_currentAccout != value)
                {
                    _currentAccout = value;
                    RaisePropertyChanged("CurrentAccount");
                    if (_currentAccout != null)
                    {
                        this.IsReady = true;
                        RaisePropertyChanged("IsReady");
                    }
                    else
                    {
                        this.IsReady = false;
                        RaisePropertyChanged("IsReady");
                    }
                }
            }
        }
        private BackgroundWorker _worker = new BackgroundWorker();

        public AccountSettingsView()
        {
            InitializeComponent();
            this._title = "Account Settings";
            // for testing purposes. To be removed
            // hack to handle the closing event of the main window
            Application.Current.MainWindow.Closing+= new System.ComponentModel.CancelEventHandler(OnMainWindowClosing);
            
            // moved to SerializeAccounts
            //this._accountRepository = GetAccounts(new Random().Next(4,6));
            _worker.DoWork += new DoWorkEventHandler(LoadAccountsAsync);
            _worker.RunWorkerAsync();
            this.comboTickFrequency.ItemsSource = Enum.GetValues(typeof(TickFrequency));
            this.comboCurrencyPair.ItemsSource = Enum.GetValues(typeof(CurrencyEnum));
            this.DataContext = this;
            FileInfo fi = new FileInfo(RXSStationFileNames.ImagesPath + "Settings.png");
            if (fi.Exists)
            {
                this.Icon = new BitmapImage(new Uri(fi.FullName, UriKind.RelativeOrAbsolute));
            }
        }

        void LoadAccountsAsync(object sender, DoWorkEventArgs e)
        {
            DeSerializeAccounts();
        }
        void SaveAccountsAsync(object sender, DoWorkEventArgs e)
        {
            SerializeAccounts();
        }

        void OnMainWindowClosing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            MessageBoxResult result;
            // Ask the end user if the session should be left open or it should be closed
            if (this.CurrentAccount != null && this.CurrentAccount.CurrentSession.ActiveOrders.Count > 0)
            {
                result = MessageBox.Show("You have active orders. Do you want to keep the session open?",
                    "Session has active orders!", MessageBoxButton.YesNoCancel, MessageBoxImage.Question);
                switch (result)
                {
                    case MessageBoxResult.Cancel:
                        {
                            e.Cancel = true;
                            return;
                        }
                    case MessageBoxResult.No:
                        {
                            // close a session
                            this.CurrentAccount.CurrentSession.IsOpen = false;
                            this.CurrentAccount.CurrentSession.TimeStampEnd = DateTime.Now;
                            this.CurrentAccount.CurrentSession.ActiveOrders.Clear();
                            break;
                        }
                    case MessageBoxResult.None:
                        break;
                    case MessageBoxResult.OK:
                        break;
                    case MessageBoxResult.Yes:
                        {
                            // leave the session open
                            this.CurrentAccount.CurrentSession.IsOpen = true;
                            break;
                        }
                    default:
                        break;
                }
                
              
            }
            // save accounts
            SerializeAccounts();

            Application.Current.Shutdown();
        }
        
        public AccountSettingsView(IEventAggregator eventAggregator, IRegionManager regionManager)
            : this()
        {
            _eventAggregator = eventAggregator;

            this.SimulationStarted+=new EventHandler(OnSimulationStarted);
        }

        #region Testing services

        private TreeViewItem _lastSelected = new TreeViewItem();
        private void DeSerializeAccounts()
        {
            BinaryFormatter formatter = new BinaryFormatter();
            FileInfo file = new FileInfo(@"..\..\..\Modules\Accounts.bin");

            if (File.Exists(file.FullName))
            {
                FileStream fs = new FileStream(file.FullName, FileMode.Open);
                using (fs)
                {
                    this.Accounts = (ObservableCollection<Account>)formatter.Deserialize(fs);
                }
            }
            else
            {
                // Create a file and create some testing accounts
                FileStream fs = new FileStream(file.FullName, FileMode.Create);
                fs.Close();
                this.Accounts = GetAccounts();
            }
        }
        private void SerializeAccounts()
        {
            BinaryFormatter formatter = new BinaryFormatter();
            FileInfo file = new FileInfo(@"..\..\..\Modules\Accounts.bin");

            if (File.Exists(file.FullName))
            {
                FileStream fs = new FileStream(file.FullName, FileMode.Create);
                using (fs)
                {
                    formatter.Serialize(fs, this.Accounts);
                }
            }
        }
        ObservableCollection<Account> GetAccounts()
        {
            ObservableCollection<Account> tempAccounts = new ObservableCollection<Account>();
            Account ac1 = new Account("TestAccount", new Balance(10000));
            Account ac2 = new Account("TestAccount2", new Balance(12000));
            tempAccounts.Add(ac1);
            tempAccounts.Add(ac2);

            return tempAccounts;
        }

        private void listAccounts_Selected(object sender, RoutedEventArgs e)
        {
            //IMPORTANT
            // this hack is required for now, as only accounts can be selected!
            if ((sender as TreeView).SelectedItem.GetType() != typeof(Account))
            {
                if (_lastSelected.IsSelected)
                {
                    (e.OriginalSource as TreeViewItem).IsSelected = false;
                }
                else
                {
                    (e.OriginalSource as TreeViewItem).IsSelected = false;
                    _lastSelected.IsSelected = true;
                    return;
                }
            }

            _lastSelected = e.OriginalSource as TreeViewItem;
        }


        #endregion //testin services

        #region ITileViewItem Members
        private string _title;
        public string Title
        {
            get { return _title; }
            set { _title = value; }
        }

        public object Icon 
        { 
            get; 
            set; 
        }

        private bool _isReady;
        public bool IsReady
        {
            get { return _isReady; }
            set
            {
                _isReady = value;
            }
        }

        #endregion

        #region IAccountRepository Members

        public ObservableCollection<Account> Accounts
        {
            get
            {
                return _accountRepository;
            }
            set
            {
                _accountRepository = value;
                RaisePropertyChanged("Accounts");

                if (_accountRepository != null)
                {
                    this.IsReady = true;
                    RaisePropertyChanged("IsReady");
                }
                else
                {
                    this.IsReady = false;
                    RaisePropertyChanged("IsReady");
                }
            }
        }

        #endregion

        private void OnSimulationinItialized(object sender, RoutedEventArgs e)
        {
            SimulationMode mode = rbTesting.IsChecked == true ? SimulationMode.Testing : SimulationMode.History;
            CurrencyEnum currency = (CurrencyEnum)Enum.Parse(typeof(CurrencyEnum), comboCurrencyPair.SelectedItem.ToString());
            TickFrequency frequency = (TickFrequency)Enum.Parse(typeof(TickFrequency), comboTickFrequency.SelectedItem.ToString());

            this.CurrentAccount = listAccounts.SelectedItem as Account;

            if (this.CurrentAccount == null)
                return;
            // no current session. When account starts for first time!
            if (this.CurrentAccount.CurrentSession == null)
            {
                Session session = new Session(DateTime.Now, currency);
                this.CurrentAccount.CurrentSession = session;
                this.CurrentAccount.Sessions.Add(session);
            }
            else
            {
                // account has already been started once.
                // Check if there is an opened session or not
                if (this.CurrentAccount.CurrentSession.IsOpen == true)
                {
                    bool startNewSession = MessageBox.Show("There is already an opened session. Do you want to start a new session?", "Start new Session", MessageBoxButton.YesNo) == MessageBoxResult.Yes ? true : false;
                    if (startNewSession)
                    {
                        // close the current opened session and create a new one
                        this.CurrentAccount.CurrentSession.IsOpen = false;
                        Session session = new Session(DateTime.Now, currency);
                        this.CurrentAccount.CurrentSession = session;
                        this.CurrentAccount.Sessions.Add(session);
                    }
                    else
                    {
                        // continue with last session's configuration
                        currency = this.CurrentAccount.CurrentSession.CurrencySymbol;
                    }
                }
                else
                {
                    // set what is already selected in the view
                    Session session = new Session(DateTime.Now, currency);
                    this.CurrentAccount.CurrentSession = session;
                    this.CurrentAccount.Sessions.Add(session);
                }
            }
            Simulation simulation = new Simulation(mode, currency, frequency, this.CurrentAccount);
            // Raise the event : New Simulation
            SimulationStarted(simulation,null);
        }

        #region Publishing Events

        void OnSimulationStarted(object sender, EventArgs e)
        {
            _eventAggregator.GetEvent<SimulationStartedEvent>().Publish(sender as Simulation);
        }

        #endregion

        private void OnAccountCreated(object sender, RoutedEventArgs e)
        {
            string _erroMessage = ValidateNewUser(tbUsername.Text);
            if (!String.IsNullOrEmpty(_erroMessage))
            {
                MessageBox.Show(_erroMessage, "New Account Validation");
                return;
            }
            Account account = new Account(tbUsername.Text, new Balance(10000)) { Description = tbDescription.Text };
            this.Accounts.Add(account);
        }

        /// <summary>
        /// Validates the newly created account
        /// </summary>
        /// <param name="username">New Username</param>
        /// <returns></returns>
        private string ValidateNewUser(string username)
        {
            StringBuilder errorMessage = new StringBuilder();
            if (String.IsNullOrEmpty(username))
            {
                errorMessage.Append("Username required!" + Environment.NewLine);
            }

            var accounts = from acc in this.Accounts
                           where acc.Name == username
                           select acc;
            if (accounts.Count() > 0)
                errorMessage.Append("Username exists!");
                return errorMessage.ToString();

        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;
        public void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion
        


    }
}
